package de.uni_saarland.coli.doclists.suffixtree;

import de.uni_saarland.coli.doclists.document.IndexDocument;
import de.uni_saarland.coli.doclists.index.Index;

/**
 * 
 * @author stefan
 * 
 * 
 *         suffix tree construciton in linear time (document size)? should be
 *         ukkonen ? (have to check the algorithm again)
 * 
 *         needs and initalized index (see unit test for examples)
 */
public class TreeConstuctor {
	Suffix currentSuffix;
	int len;

	public TreeConstuctor() {
		this.currentSuffix = new Suffix();
	}

	private void addNextPrefix(int pos) {
		int currentParentNodeID;
		int lastParentNodeID = -1;

		for (;;) {

			STreeEdge edge;
			currentParentNodeID = this.currentSuffix.getMainNode();
			edge = Index.getEdgeMap().find(this.currentSuffix.getMainNode(),
					this.currentSuffix.getToken(pos));

			
			if (this.currentSuffix.isExplicit()) {
				if (edge != null) {
			
					break;
				}
			} else {
				edge = Index.getEdgeMap().find(
						this.currentSuffix.getMainNode(),
						this.currentSuffix.getToken(this.currentSuffix
								.getStart()));

				int span = this.currentSuffix.getEnd()
						- this.currentSuffix.getStart();
				if (edge != null
						&& Index.getDocumentManager()
								.getDocument(edge.getBaseDocID())
								.getTermAt(edge.getFirstTokenIndex() + span + 1) == this.currentSuffix
								.getToken(pos)) {

					break;
				}

				if (edge != null) {
					currentParentNodeID = edge.split(this.currentSuffix);
				}
			}
			STreeEdge newEdge = Index.getEdgeMap().createEdge(this.currentSuffix.getDocID(), pos,
					len, currentParentNodeID);

			STreeNode node = Index.getNodeMap().getNode(newEdge.getEndNode());
			node.addDoc(this.currentSuffix.getDocID(), pos);

			
			if (lastParentNodeID > 0) {
				Index.getNodeMap().getNode(lastParentNodeID)
						.setSuffixNode(currentParentNodeID);
			}
			lastParentNodeID = currentParentNodeID;

			if (this.currentSuffix.getMainNode() == 0)
				this.currentSuffix.increaseStart();
			else {
				this.currentSuffix.setMainNode(Index.getNodeMap()
						.getNode(this.currentSuffix.getMainNode())
						.getSuffixNode());
			}
			this.currentSuffix.canonize();

		}
		if (lastParentNodeID > 0)
			this.currentSuffix.setMainNode(Index.getNodeMap()
					.getNode(this.currentSuffix.getMainNode()).getSuffixNode());

		this.currentSuffix.increaseEnd();
		this.currentSuffix.canonize();
	}

	/**
	 * adds a document to the suffix tree
	 * 
	 * @param doc
	 *            a new document
	 */
	public void addDocumentToSTree(IndexDocument doc) {
		if (Index.getNodeMap().getNode(0) == null)
			Index.getNodeMap().createNode().getNodeID();
		this.len = doc.size() + 1;

		this.currentSuffix.setDoc(doc);
		this.currentSuffix.setStart(0);
		this.currentSuffix.setEnd(-1);
		this.currentSuffix.setMainNode(0);

		for (int i = 0; i < this.len; i++) {
			this.addNextPrefix(i);
		}
	}

	/**
	 * Prints information related to the current construction edges, links,
	 * starting edge and last added token
	 */
	protected void printInfo() {
		System.out.println("--------");
		// System.out.println("Added '"
		// + Index.getTermDictionary().getValue(this.currentToken) + "'");
		System.out.println("\nEdges:");
		System.out.println(Index.getEdgeMap().toString());
	}
}
